/* linkit.js
 * By François Leporcq
 * MIT Licensed.
 * JavaScript Class, AbstractClass , Interface and Inheritance
 * Inspired by John Resig Simple JavaScript Inheritance (http://ejohn.org/blog/simple-javascript-inheritance/)
 */
(function(){
    var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
    // The base Class implementation (does nothing)
    $Class = function(){};


    var implement = function(interfaces){
        var classInterfaces = new Array();

        initializing = true;
        var prototype = new this();
        initializing = false;

        for(var i = 0 ; i < interfaces.length ; i++){

            initializing = true;
            var _interface = new interfaces[i]();
            initializing = false;

            if(_interface instanceof $Interface){
                classInterfaces.push(interfaces[i]);
                for (var name in _interface) {
                    if(typeof _interface[name] == "function" && typeof prototype[name] == "undefined"){
                        throw new Error("Class '" + prototype.getClassName() + "' (implementing " + _interface.getClassName() + " interface) must define a '" + name +"' method");
                    }

                }
            }else{
                throw new Error("Class '" + _interface.getClassName() + "' is not an interface, class '" + prototype.getClassName() + "' cannot implemente it");
            }
            delete _interface;
        }
        delete prototype;
        this.prototype.interfaces = classInterfaces;
        return this;
    }

    $Class.prototype.implementationOf = function(_interface){
        if(!this.interfaces){
            return false;
        }
        for(var i = 0 ; i< this.interfaces.length ; i++){
            if(this.interfaces[i] === _interface){
                return true;
            }
        }
        return false;
    }

    // Create a new Class that inherits from this class
    $Class.extend = function(prop, _abstract) {

        if(!prop["_className"]){
            throw new Error("A class must have a _className property");
        }
        var _super = this.prototype;
        // Instantiate a base class (but only create the instance,
        // don't run the init constructor)
        initializing = true;
        var prototype = new this();
        initializing = false;
        // Copy the properties over onto the new prototype
        for (var name in prop) {
            // Check if we're overwriting an existing function
            prototype[name] = typeof prop[name] == "function" &&
                typeof _super[name] == "function" && fnTest.test(prop[name]) ?
                (function(name, fn){
                    return function() {
                        var tmp = this._super;

                        // Add a new ._super() method that is the same method
                        // but on the super-class
                        this._super = _super[name];

                        // The method only need to be bound temporarily, so we
                        // remove it when we're done executing
                        var ret = fn.apply(this, arguments);
                        this._super = tmp;

                        return ret;
                    };
                })(name, prop[name]) :
                prop[name];
        }

        // The dummy class constructor
        function $Class() {

            // All construction is actually done in the init method
            if ( !initializing && this.init ){
                if(_abstract){
                    throw new Error("Cannot instantiate abstract class '" + this.getClassName() + "'");
                }else{
                    this.init.apply(this, arguments);
                }
            }
        }

        // Populate our constructed prototype object
        $Class.prototype = prototype;
        delete prototype;
        // Enforce the constructor to be what we expect
        $Class.prototype.constructor = $Class;

        // And make this class extendable
        $Class.extend = arguments.callee;
        $Class.implement = implement;

        return $Class;
    };
})();
$Class.prototype._className = "Class";
$Class.prototype.getClassName= function(){
    return this._className;
}
var $Interface = $Class.extend({
    _className:"Interface",
    init: function(){
        throw new Error("Cannot instantiate interface '" + this.getClassName() + "'");
    }
});

ObjectUtils = {
    clone: function (obj) {
        var newObj = (obj instanceof Array) ? [] : {};
        for (i in obj) {
            if (i == 'clone') continue;
            if (obj[i] && typeof obj[i] == "object") {
                newObj[i] = this.clone(obj[i]);
            } else newObj[i] = obj[i]
        } return newObj;
    }
}
